#ifndef _Rand48_H_
#define _Rand48_H_

#pragma once
#include "Math.h"
//#include "MTRand.h"

#define MNWZ 0x100000000
#define ANWZ 0x5DEECE66D
#define CNWZ 0xB16

namespace Rand {
	static unsigned long long seed = 192468214654342896;

	inline double drand48(void) {
		seed = (ANWZ * seed + CNWZ) & 0xFFFFFFFFFFFFLL;
		unsigned int x = unsigned int(seed >> 16);
		return ((double)x / (double)MNWZ);
	}

	inline void srand48(unsigned int i) {
		seed = (((long long int)i) << 16) | rand();
	}

	inline double randNormal() {
		double u = drand48() * 2 - 1;
		double v = drand48() * 2 - 1;
		double r = u * u + v * v;
		if (r == 0 || r > 1) return randNormal();
		double c = sqrt(-2 * log(r) / r);
		return u * c;
	}

	//static MTRand_int32 mtRand(192468213UL);

	template <class T>
	inline T randIn(T min, T max) {
		return min + drand48() * (max - min);
	}

	template <class T>
	inline T randIntIn(T min, T max) {
		return min + (rand() % (1 + max - min));
	}
}

#define RANDINT rand()
#define RAND Rand::drand48()
#define RANDSEED(seed) Rand::srand48(seed)
#define RANDINTSEED(seed) srand(seed)
#define RANDNORMAL Rand::randNormal()

/*#define RANDINT Rand::mtRand()
#define RAND Rand::mtRand.random_double()
#define SEEDRAND(seed) Rand::mtRand.seed(seed)
#define SEEDRANDINT(seed) SEEDRAND(seed)*/

#define RANDINTIN(min,max) Rand::randIntIn(min,max)
#define RANDIN(min,max) Rand::drand48(min,max)

#define RANDN2(mu, sigma) ((mu) + (RANDINT % 2 ? -1.0 : 1.0)*(sigma)*fastPow(-log(0.99999 * RAND), 0.5))
#define RANDN RANDN2(0, 1.0)

#endif // _rand48_H_